#include <boost/lexical_cast.hpp>

#include <iostream>
#include <vector>

using namespace std;

#include "ventana.h"

Ventana::Ventana () : Gosu::Window(800, 600, false){

    // Cargamos los recursos
    fondo = new Gosu::Image(graphics(), Gosu::sharedResourcePrefix() + L"media/fondo.png");
    pala = new Gosu::Image(graphics(), Gosu::sharedResourcePrefix() + L"media/pala.png");
    bola = new Gosu::Image(graphics(), Gosu::sharedResourcePrefix() + L"media/bola.png");
    bloque = new Gosu::Image(graphics(), Gosu::sharedResourcePrefix() + L"media/bloque.png");

    //@@RELLENAME@@
    fuente = NULL;


    // Inicializamos la caja de colisión para la pala, inicialmente centrada
    cajaPala.x = 57;
    cajaPala.y = 568;
    cajaPala.w = pala -> width();
    cajaPala.h = pala -> height();

    // Inicializamos la caja de colisión para la bola. La posición dependerá del
    // estado en el que esté el juego
    cajaBola.w = bola -> width();
    cajaBola.h = bola -> height();

    // Ponemos el juego en el estado inicial
    estadoActual = ESTADO_INICIAL;

    // Reiniciamos la velocidad inicial
    bolaVelX = 0;
    bolaVelY = 0;

    // Rellenamos el tablero inicial
    rellenarTablero();
    
    // Reiniciamos la puntuación
    puntuacion = 0;
}

Ventana::~Ventana(){
    // Liberamos los recursos
    delete fondo;
    delete pala;
    delete bola;
    delete bloque;

    if(fuente != NULL)
        delete fuente;
}

void Ventana::rellenarTablero(){
    // Reiniciamos el contador de bloques restantes
    bloquesRestantes = 50;
    
    // Rellenamos el tablero de casillas, inicializando las cajas de colisiones
    // de cada bloque con su posición correspondiente en el tablero
    for(unsigned i = 0; i < 5; ++i){
        for(unsigned j = 0; j < 10; ++j){
            tablero[i][j].tipo = i + 1;
            tablero[i][j].x = PRIMER_BLOQUE_X + LADO_BLOQUE * j;
            tablero[i][j].y = PRIMER_BLOQUE_Y + LADO_BLOQUE * i;
        }
    }
}

void Ventana::update(){

    // Si no quedan bloques por derribar, reiniciamos el juego
    if(bloquesRestantes == 0){
        rellenarTablero();
        estadoActual = ESTADO_INICIAL;
    }

    // Leemos la posición horizontal del ratón

    //@@RELLENAME@@
    float mouseX = 0;

    // Si el ratón está dentro de los límites, la pala lo sigue
    if(mouseX >= PARED_IZQUIERDA && mouseX <= RECORRIDO_PALA){
        cajaPala.x = mouseX;
    }else if (mouseX < PARED_IZQUIERDA){
        cajaPala.x = PARED_IZQUIERDA;
    }else{
        cajaPala.x = RECORRIDO_PALA;
    }

    // En el estado inicial, la bola se mantiene en el centro de la pala
    if(estadoActual == ESTADO_INICIAL){
        cajaBola.x = cajaPala.x + cajaPala.w / 2 - cajaBola.w / 2;
        cajaBola.y = cajaPala.y - cajaBola.h - 3;
    }

    // En el estado en movimiento, la bola se mueve (lógicamente)
    else if(estadoActual == ESTADO_MOVIMIENTO){
        cajaBola.x += bolaVelX;
        cajaBola.y += bolaVelY;
    

        /*** COLISIONES CON PAREDES **/
        // Pared izquierda
        if(cajaBola.x < PARED_IZQUIERDA){
            bolaVelX = -bolaVelX;
            cajaBola.x = PARED_IZQUIERDA;
        }

        // Pared derecha
        else if(cajaBola.x > PARED_DERECHA - cajaBola.w){
            bolaVelX = -bolaVelX;
            cajaBola.x = PARED_DERECHA - cajaBola.w;
        }

        // Pared superior
        else if(cajaBola.y < PARED_SUPERIOR){
            bolaVelY = -bolaVelY;
            cajaBola.y = PARED_SUPERIOR;
        }

        // límite de abajo
        else if(cajaBola.y > PARED_INFERIOR){
            // pierde una vida o lo que sea
            estadoActual = ESTADO_INICIAL;
        }

        /** COLISIÓN CON LA PALA **/
        // Si hay colisión cuando la bola está yendo hacia abajo
        if(cajaBola.y < cajaPala.y && cajaPala.colisionaCon(cajaBola) && bolaVelY > 0){
            bolaVelY = -bolaVelY; // easy way

            // En qué zona de la pala ha golpeado   

            // Calculamos el punto central de la pala
            float puntoCentralPala = cajaPala.x + cajaPala.w / 2;

            // Calculamos el punto central de la bola
            float puntoCentralBola = cajaBola.x + cajaBola.w / 2;

            // Vemos la distancia de la bola al centro
            float distanciaDelCentro = puntoCentralBola - puntoCentralPala;

            // Normalizamos esa distancia a [-1,1]
            float distanciaNormalizada = Gosu::clamp(distanciaDelCentro / (cajaPala.w / 2), 
                                                     -1.f, 1.f);

            // Calculamos el ángulo resultante en [-55,55]
            float anguloResultante = distanciaNormalizada * ANGULO_REBOTE;

            // Descomponemos el ángulo en sus componentes horizontal y vertical
            bolaVelX = Gosu::offsetX(anguloResultante, VELOCIDAD);
            bolaVelY = Gosu::offsetY(anguloResultante, VELOCIDAD);
        }

        /** COLISIONES CON LOS BLOQUES **/
        bool bloqueColisionado = false;

        // Comprobamos todos los bloques
        for(unsigned i = 0; i < 5 && !bloqueColisionado; ++i){
            for(unsigned j = 0; j < 10 && !bloqueColisionado; ++j){

                // Si es un bloque vacío, pasamos
                if(tablero[i][j].tipo == BLOQUE_VACIO){
                    continue;
                }

                // Vemos si ha habido colisión, y en tal caso, con qué lado ha chocado
                int LadoColision = tablero[i][j].tocado(cajaBola);

                if(LadoColision == 0){
                    // No hay colisión
                    continue;
                }

                else{
                    // Hay colisión
                    bloqueColisionado = true;

                    // Borramos el bloque
                    tablero[i][j].tipo = BLOQUE_VACIO;

                    // Reducimos el contador de bloques restantes
                    bloquesRestantes --;

                    // Aumentamos la posición
                    puntuacion += 10;

                    // Si ha dado con el lado superior o inferior, invertimos la velocidad vertical
                    if(LadoColision == 1){
                        bolaVelY = -bolaVelY;
                    }
                    // Si ha dado con un lateral, invertimos la velocidad horizontal
                    else{
                        bolaVelX = -bolaVelX;
                    }
                }
            }
        }
    }

}

void Ventana::draw(){

    // Imprimimos el fondo
    // @@RELLENAME@@

    // Pintamos la pala
    pala -> draw(cajaPala.x, cajaPala.y, 1);

    // Pintamos la bola
    bola -> draw(cajaBola.x, cajaBola.y, 1);

    // Recorremos cada uno de los bloques para pintarlos
    for(unsigned i = 0; i < 5; ++i){
        for(unsigned j = 0; j < 10; ++j){

            // Si el bloque es transparente, no lo pintamos
            if(tablero[i][j].tipo == BLOQUE_VACIO) continue;

            // Según el tipo de bloque, usamos un color u otro
            Gosu::Color bloqueColor = 0x0;

            // Miramos qué tipo de bloque es
            switch(tablero[i][j].tipo){
            case BLOQUE_NARANJA:
                bloqueColor = 0xffff6600;
                break;

            case BLOQUE_AZUL:
                bloqueColor = 0xff0095ff;
                break;

            case BLOQUE_VERDE:
                bloqueColor = 0xff3bff00;
                break;

            case BLOQUE_ROJO:
                bloqueColor = 0xffff0000;
                break;

            case BLOQUE_AMARILLO:
                bloqueColor = 0xffffff00;
                break;
            }

            // Imprimimos la imagen del bloque utilizando el color que hemos elegido
            bloque -> draw(tablero[i][j].x, tablero[i][j].y, 2); //@@RELLENAME@@
        }
    }

    // Imprimimos el texto con la puntuación
    if(fuente != NULL)
        fuente -> draw(boost::lexical_cast<wstring>(puntuacion),
                       596, 100, 3);
}

void Ventana::buttonDown(Gosu::Button B){

    // Si se pulsa la tecla Escape, salimos
    if(B == Gosu::kbEscape){
        close();
    } 
    
    // Si estamos en el estado inicial y se pulsa el ratón o el espacio
    // Comenzamos el movimiento de la bola
    else if(estadoActual == ESTADO_INICIAL && (B == Gosu::kbSpace || B == Gosu::msLeft)){
        // Pasamos al estado de movimiento
        estadoActual = ESTADO_MOVIMIENTO;
 
        // Le aplicamos una velocidad totalmente vertical
        bolaVelY = - VELOCIDAD;
        bolaVelX = 0;
    }
}

bool Ventana::needsCursor() const{
    // Si devolvemos false, el cursor se esconde.
    return false;
}
